perf(detail): render slides + thumbnail strip from sized variants, not full-res preview#522
Merged
Merged
Conversation
…t full-res preview The real cause of the detail-view jank (flame graph) is image decoding, not React or WebGL: on this deployment preview compression is off, so `preview_url` is the full-resolution (~30MP) image. The in-place carousel rendered the raw preview_url for up to 5 visible slides plus 21 thumbnail-strip cells, so opening an album decoded ~600 megapixels and every switch decoded a ~45MP image — device-bound jank (fast headless machines hid it; real devices stalled). Route both through the existing variant system (the same one the grid uses): - ProgressiveImage inline (non-zoom) preview now serves a ~1280 variant via makeVariantLoader instead of preview_url — a fixed width (not next/image DPR srcset) so retina screens don't get pushed to the 2560 tier. ~30MP → ~1.1MP per slide. The zoom path is untouched (still loads the original for pixel-peeping). Falls back to preview_url only when a photo has no variants, and an onError steps variant → preview_url, never up to the original. - Thumbnail strip cells (48px) serve the smallest 320 tier (requested at width 96); no variants (or onError) → decoded blurhash, never the full-res preview_url. ~30MP → ~0.07MP per thumbnail. Mirrors the variant→fallback→blurhash cascade in blur-image.tsx. No change to the zoom/WebGL path, the GL-context LRU, or the FLIP transition's target measurement. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why (the actual root cause)
The detail-view jank that persisted after the histogram PR is image decoding, per flame-graph profiling. On this deployment preview compression is off (
previewImageMaxWidthLimitunset), sopreview_urlis the full-resolution (~30MP) image. The in-place carousel rendered the rawpreview_urlfor up to 5 visible slides plus 21 thumbnail-strip cells, so:This is device-bound (fast headless machines hid it at ~67ms; slower real devices stalled). The earlier histogram PR fixed per-switch recompute but never touched decoding, so the jank remained.
Fix — route both through the existing variant system (same one the grid uses)
makeVariantLoaderinstead ofpreview_url. A fixed width (not next/image DPR srcset) so retina screens aren't pushed to the 2560 tier. ~30MP → ~1.1MP per slide. The zoom path is untouched (still loads the original for pixel-peeping). Falls back topreview_urlonly when a photo has no variants; anonErrorsteps variant →preview_url, never up to the original.onError) → decoded blurhash, never the full-respreview_url. ~30MP → ~0.07MP per thumbnail.Mirrors the variant → fallback → blurhash cascade in
blur-image.tsx. ThemakeVariantLoadermin(ceilToTier, readyMaxWidth)clamp keeps it safe during backfill (serves a softer-but-smaller tier, never a 404).Out of scope / guardrails
[data-flip-target]measurement.previewImageMaxWidthLimitwould downsample future uploads' previews, but rendering from variants already covers existing photos so it isn't required.Verification
tsc+eslintclean for changed files. Expected post-deploy (throttled re-trace): open decode drops from ~600MP to single-digit MP, per-switch decode from ~45MP to ~1MP. Prerequisite being confirmed in parallel: the albums arevariants_ready(a scan is underway; any stragglers without variants are a backfill subset, not a rendering issue).